<?php

namespace app\admin\controller;

use app\common\controller\Backend;
use app\common\exception\UploadException;
use app\common\library\Upload;
use fast\Random;
use think\addons\Service;
use think\Cache;
use think\Config;
use think\Db;
use think\Lang;
use think\Loader;
use think\Response;
use think\Validate;

/**
 * Ajax异步请求接口
 * @internal
 */
class Ajax extends Backend
{

    protected $noNeedLogin = ['lang'];
    protected $noNeedRight = ['*'];
    protected $layout = '';

    public function _initialize()
    {
        parent::_initialize();

        //设置过滤方法
        $this->request->filter(['trim', 'strip_tags', 'htmlspecialchars']);
    }

    /**
     * 加载语言包
     */
    public function lang()
    {
        $this->request->get(['callback' => 'define']);
        $header = ['Content-Type' => 'application/javascript'];
        if (!config('app_debug')) {
            $offset = 30 * 60 * 60 * 24; // 缓存一个月
            $header['Cache-Control'] = 'public';
            $header['Pragma'] = 'cache';
            $header['Expires'] = gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
        }

        $controllername = $this->request->get('controllername');
        $lang = $this->request->get('lang');
        
        if (!$lang || !in_array($lang, config('allow_lang_list')) || !$controllername || !preg_match("/^[a-z0-9_\.\/]+$/i", $controllername)) {
            return jsonp(['errmsg' => '参数错误'], 200, [], ['json_encode_param' => JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE]);
        }

        $controllername = input("controllername");
        $className = Loader::parseClass($this->request->module(), 'controller', $controllername, false);

        //存在对应的类才加载
        if (class_exists($className)) {
            $this->loadlang($controllername);
        } else {
            // 如果类不存在，尝试直接加载语言包
            $langFile = APP_PATH . $this->request->module() . '/lang/zh-cn/' . str_replace('.', '/', $controllername) . '.php';
            if (file_exists($langFile)) {
                Lang::load($langFile);
            }
        }

        return jsonp(Lang::get(), 200, $header, ['json_encode_param' => JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE]);
    }

    /**
     * 上传文件 =====yzs 上传图片
     */
    public function upload()
    {
        Config::set('default_return_type', 'json');

        //必须还原upload配置,否则分片及cdnurl函数计算错误
        Config::load(APP_PATH . 'extra/upload.php', 'upload');

        // 获取width和height参数，优先从URL参数获取，其次从POST参数获取
        $width = $this->request->param("width/d") ?? $this->request->post("image_width/d") ?? 0;
        $height = $this->request->param("height/d") ?? $this->request->post("image_height/d") ?? 0;
        
        // 验证裁切参数：width和height都必须大于50才进行裁切
        $shouldCrop = ($width > 50 && $height > 50);

        $chunkid = $this->request->post("chunkid");
        if ($chunkid) {
            if (!Config::get('upload.chunking')) {
                $this->error(__('Chunk file disabled'));
            }
            $action = $this->request->post("action");
            $chunkindex = $this->request->post("chunkindex/d");
            $chunkcount = $this->request->post("chunkcount/d");
            $filename = $this->request->post("filename");
            $method = $this->request->method(true);
            if ($action == 'merge') {
                $attachment = null;
                //合并分片文件
                try {
                    $upload = new Upload();
                    $attachment = $upload->merge($chunkid, $chunkcount, $filename);
                    
                    // 分片上传合并后也进行图片裁切
                    if ($shouldCrop && $this->isImageFile($attachment->url)) {
                        $this->resizeImage($attachment->url, $width, $height);
                    }
                } catch (UploadException $e) {
                    $this->error($e->getMessage());
                }
                $this->success(__('Uploaded successful'), '', ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]);
            } elseif ($method == 'clean') {
                //删除冗余的分片文件
                try {
                    $upload = new Upload();
                    $upload->clean($chunkid);
                } catch (UploadException $e) {
                    $this->error($e->getMessage());
                }
                $this->success();
            } else {
                //上传分片文件
                //默认普通上传文件
                $file = $this->request->file('file');
                try {
                    $upload = new Upload($file);
                    $upload->chunk($chunkid, $chunkindex, $chunkcount);
                } catch (UploadException $e) {
                    $this->error($e->getMessage());
                }
                $this->success();
            }
        } else {
            $attachment = null;
            //默认普通上传文件
            $file = $this->request->file('file');

            try {
                $upload = new Upload($file);
                $attachment = $upload->upload();

                // 如果指定了有效的图片尺寸且上传的是图片文件，进行裁剪处理
                if ($shouldCrop && $this->isImageFile($attachment->url)) {
                    $this->resizeImage($attachment->url, $width, $height);
                }
            } catch (UploadException $e) {
                $this->error($e->getMessage());
            }

            $this->success(__('Uploaded successful'), '', ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]);
        }
    }

    //删除上传过的文件
    public function delupload()
    {
        $this->success(__('Deleted successful'));
        $url = $this->request->post("url");
        $url = str_replace(cdnurl(''), '', $url);
        $path = ROOT_PATH . 'public' . $url;
        if (file_exists($path)) {
            unlink($path);
            $this->success(__('Deleted successful'));
        } else {
            $this->error(__('File not exists'));
        }
    }

    /**
     * 检查是否为图片文件
     * @param string $url 文件URL
     * @return bool
     */
    private function isImageFile($url)
    {
        $imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'];
        $extension = strtolower(pathinfo($url, PATHINFO_EXTENSION));
        return in_array($extension, $imageExtensions);
    }

    /**
     * 调整图片尺寸
     * @param string $url 图片URL
     * @param int $width 目标宽度
     * @param int $height 目标高度
     * @return bool
     * 
     * 1. 宽图片处理 ($originalRatio > $targetRatio)

按宽度缩放：使用 $scaleY 缩放比例，确保宽度 = 目标宽度

宽度完全填充：缩放后宽度正好等于目标宽度

高度从底部开始裁剪

不裁剪上方：$cropY = 0 - 保留完整的高度内容

2. 高图片处理 ($originalRatio <= $targetRatio)

按高度缩放：使用 $scaleX 缩放比例，确保高度 = 目标高度

高度完全填充：缩放后高度正好等于目标高度

宽度从左右两侧同时裁剪相同的大小
     */
    public function resizeImage($url, $width, $height)
    {
        try {
            $imagePath = '';
            $isRemoteImage = false;
            $tempFile = '';

            // 判断是本地文件还是远程文件
            if (strpos($url, 'http://') === 0 || strpos($url, 'https://') === 0) {
                // 远程图片：下载到临时文件
                $isRemoteImage = true;
                $tempFile = sys_get_temp_dir() . '/' . uniqid('remote_img_') . '.tmp';

                // 下载远程图片
                $imageContent = file_get_contents($url);
                if ($imageContent === false) {
                    return false;
                }

                // 保存到临时文件
                if (file_put_contents($tempFile, $imageContent) === false) {
                    return false;
                }

                $imagePath = $tempFile;
            } else {
                // 本地文件：构建完整路径
                $imagePath = ROOT_PATH . 'public' . $url;

                if (!file_exists($imagePath)) {
                    return false;
                }
            }

            // 获取图片信息
            $imageInfo = getimagesize($imagePath);
            if (!$imageInfo) {
                return false;
            }

            $originalWidth = $imageInfo[0];
            $originalHeight = $imageInfo[1];
            $imageType = $imageInfo[2];

            // 如果原图尺寸已经符合要求，不需要处理
            if ($originalWidth == $width && $originalHeight == $height) {
                return true;
            }

            // 创建原图资源
            switch ($imageType) {
                case IMAGETYPE_JPEG:
                    $sourceImage = imagecreatefromjpeg($imagePath);
                    break;
                case IMAGETYPE_PNG:
                    $sourceImage = imagecreatefrompng($imagePath);
                    break;
                case IMAGETYPE_GIF:
                    $sourceImage = imagecreatefromgif($imagePath);
                    break;
                case IMAGETYPE_BMP:
                    $sourceImage = imagecreatefrombmp($imagePath);
                    break;
                case IMAGETYPE_WEBP:
                    $sourceImage = imagecreatefromwebp($imagePath);
                    break;
                default:
                    return false;
            }

            if (!$sourceImage) {
                return false;
            }

            // 创建目标图片资源
            $targetImage = imagecreatetruecolor($width, $height);

            // 保持PNG和GIF的透明度
            if ($imageType == IMAGETYPE_PNG || $imageType == IMAGETYPE_GIF) {
                imagealphablending($targetImage, false);
                imagesavealpha($targetImage, true);
                $transparent = imagecolorallocatealpha($targetImage, 255, 255, 255, 127);
                imagefilledrectangle($targetImage, 0, 0, $width, $height, $transparent);
            }

            // 计算原图和目标图的宽高比
            $originalRatio = $originalWidth / $originalHeight;
            $targetRatio = $width / $height;

            // 计算缩放比例
            $scaleX = $width / $originalWidth;
            $scaleY = $height / $originalHeight;

            // 使用较大的缩放比例，确保完全填充目标尺寸
            $scale = max($scaleX, $scaleY);

            $newWidth = intval($originalWidth * $scale);
            $newHeight = intval($originalHeight * $scale);

            // 创建临时缩放图片
            $tempImage = imagecreatetruecolor($newWidth, $newHeight);

            // 保持透明度
            if ($imageType == IMAGETYPE_PNG || $imageType == IMAGETYPE_GIF) {
                imagealphablending($tempImage, false);
                imagesavealpha($tempImage, true);
                $transparent = imagecolorallocatealpha($tempImage, 255, 255, 255, 127);
                imagefilledrectangle($tempImage, 0, 0, $newWidth, $newHeight, $transparent);
            }

            // 先将原图缩放到临时图片
            imagecopyresampled(
                $tempImage,
                $sourceImage,
                0,
                0,
                0,
                0,
                $newWidth,
                $newHeight,
                $originalWidth,
                $originalHeight
            );

            // 计算裁剪位置
            if ($originalRatio > $targetRatio) {
                // 宽图片：宽度填满，高度从底部裁剪
                $cropX = 0;  // 宽度不裁剪
                $cropY = max(0, $newHeight - $height);  // 高度从底部裁剪，保留上半部分
            } else {
                // 高图片：从上下和左右的中间裁剪，保留真正中间的部分
                $cropX = intval(($newWidth - $width) / 2);   // 宽度居中裁剪
                $cropY = intval(($newHeight - $height) / 2); // 高度居中裁剪
            }

            // 从临时图片裁剪到目标图片
            imagecopyresampled(
                $targetImage,
                $tempImage,
                0,
                0,
                $cropX,
                $cropY,
                $width,
                $height,
                $width,
                $height
            );

            // 释放临时图片内存
            imagedestroy($tempImage);

            // 确定保存路径
            $savePath = $imagePath;
            if ($isRemoteImage) {
                // 远程图片：保存到原始URL对应的本地路径
                $savePath = ROOT_PATH . 'public' . $url;

                // 确保目录存在
                $saveDir = dirname($savePath);
                if (!is_dir($saveDir)) {
                    mkdir($saveDir, 0755, true);
                }
            }

            // 保存图片
            switch ($imageType) {
                case IMAGETYPE_JPEG:
                    $result = imagejpeg($targetImage, $savePath, 90);
                    break;
                case IMAGETYPE_PNG:
                    $result = imagepng($targetImage, $savePath, 9);
                    break;
                case IMAGETYPE_GIF:
                    $result = imagegif($targetImage, $savePath);
                    break;
                case IMAGETYPE_BMP:
                    $result = imagebmp($targetImage, $savePath);
                    break;
                case IMAGETYPE_WEBP:
                    $result = imagewebp($targetImage, $savePath, 90);
                    break;
                default:
                    $result = false;
            }

            // 释放内存
            imagedestroy($sourceImage);
            imagedestroy($targetImage);

            // 清理临时文件
            if ($isRemoteImage && $tempFile && file_exists($tempFile)) {
                unlink($tempFile);
            }

            return $result;
        } catch (\Exception $e) {
            // 清理临时文件
            if (isset($tempFile) && $tempFile && file_exists($tempFile)) {
                unlink($tempFile);
            }

            // 记录错误日志
            \think\Log::error('图片裁剪失败: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * 通用排序
     */
    public function weigh()
    {
        //排序的数组
        $ids = $this->request->post("ids");
        //操作字段
        $field = $this->request->post("field");
        //操作的数据表
        $table = $this->request->post("table");
        if (!Validate::is($table, "alphaDash")) {
            $this->error();
        }
        //主键
        $pk = $this->request->post("pk");
        //排序的方式
        $orderway = strtolower($this->request->post("orderway", ""));
        $orderway = $orderway == 'asc' ? 'ASC' : 'DESC';

        $ids = explode(',', $ids);
        $prikey = $pk && preg_match("/^[a-z0-9\-_]+$/i", $pk) ? $pk : (Db::name($table)->getPk() ?: 'id');

        // 添加日志记录
        \think\Log::record('Weigh method called with ids: ' . implode(',', $ids) . ', field: ' . $field . ', table: ' . $table . ', orderway: ' . $orderway, 'debug');


        //限制更新的字段
        $field = in_array($field, ['weigh']) ? $field : 'weigh';

        // 直接按传入的ids顺序设置权重
        $weight = ($orderway == 'ASC') ? 1 : count($ids);
        foreach ($ids as $id) {
            Db::name($table)->where($prikey, $id)->update([$field => $weight]);
            $weight = ($orderway == 'ASC') ? $weight + 1 : $weight - 1;
        }

        $this->success();
    }

    /**
     * 清空系统缓存
     */
    public function wipecache()
    {
        try {
            $type = $this->request->request("type");
            switch ($type) {
                case 'all':
                    // no break
                case 'content':
                    //内容缓存
                    rmdirs(CACHE_PATH, false);
                    Cache::clear();
                    if ($type == 'content') {
                        break;
                    }
                case 'template':
                    // 模板缓存
                    rmdirs(TEMP_PATH, false);
                    if ($type == 'template') {
                        break;
                    }
                case 'addons':
                    // 插件缓存
                    Service::refresh();
                    if ($type == 'addons') {
                        break;
                    }
                case 'browser':
                    // 浏览器缓存
                    // 只有生产环境下才修改
                    if (!config('app_debug')) {
                        $version = config('site.version');
                        $newversion = preg_replace_callback("/(.*)\.([0-9]+)\$/", function ($match) {
                            return $match[1] . '.' . ($match[2] + 1);
                        }, $version);
                        if ($newversion && $newversion != $version) {
                            Db::startTrans();
                            try {
                                \app\common\model\Config::where('name', 'version')->update(['value' => $newversion]);
                                \app\common\model\Config::refreshFile();
                                Db::commit();
                            } catch (\Exception $e) {
                                Db::rollback();
                                exception($e->getMessage());
                            }
                        }
                    }
                    if ($type == 'browser') {
                        break;
                    }
            }
        } catch (\Exception $e) {
            $this->error($e->getMessage());
        }

        \think\Hook::listen("wipecache_after");
        $this->success();
    }

    /**
     * 读取分类数据,联动列表
     */
    public function category()
    {
        $type = $this->request->get('type', '');
        $pid = $this->request->get('pid', '');
        $where = ['status' => 'normal'];
        $categorylist = null;
        if ($pid || $pid === '0') {
            $where['pid'] = $pid;
        }
        if ($type) {
            $where['type'] = $type;
        }

        $categorylist = Db::name('category')->where($where)->field('id as value,name')->order('weigh desc,id desc')->select();

        $this->success('', '', $categorylist);
    }

    /**
     * 读取省市区数据,联动列表
     */
    public function area()
    {
        $params = $this->request->get("row/a");
        if (!empty($params)) {
            $province = isset($params['province']) ? $params['province'] : null;
            $city = isset($params['city']) ? $params['city'] : null;
        } else {
            $province = $this->request->get('province');
            $city = $this->request->get('city');
        }
        $where = ['pid' => 0, 'level' => 1];
        $provincelist = null;
        if ($province !== null) {
            $where['pid'] = $province;
            $where['level'] = 2;
            if ($city !== null) {
                $where['pid'] = $city;
                $where['level'] = 3;
            }
        }
        $provincelist = Db::name('area')->where($where)->field('id as value,name')->select();
        $this->success('', '', $provincelist);
    }

    /**
     * 生成后缀图标
     */
    public function icon()
    {
        $suffix = $this->request->request("suffix");
        $suffix = $suffix ? $suffix : "FILE";
        $data = build_suffix_image($suffix);
        $header = ['Content-Type' => 'image/svg+xml'];
        $offset = 30 * 60 * 60 * 24; // 缓存一个月
        $header['Cache-Control'] = 'public';
        $header['Pragma'] = 'cache';
        $header['Expires'] = gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
        $response = Response::create($data, '', 200, $header);
        return $response;
    }

}
